<template>
  <div class="panorama-container">
    <div id="panorama" style="width: 800px; height: 500px; float: left" />
    <div style="width: auto; box-sizing: border-box">
      <el-button type="primary" style="margin: 0 0 10px 10px" @click="startAddHotspot">
        添加热点
      </el-button>
      <div style="width: auto; height: 454px; overflow-y: auto">
        <div v-for="(hotspot, index) in hotspots" :key="index" class="hotspot-item">
          <el-form :ref="`form-${index}`" :model="hotspot" :rules="getRules(hotspot.job)" label-width="80px">
            <el-form-item label="Pitch" prop="pitch" class="form-item">
              <el-input-number v-model="hotspot.pitch" :step="1" @blur="handleUpdateHotspot" />
            </el-form-item>
            <el-form-item label="Yaw" prop="yaw" class="form-item">
              <el-input-number v-model="hotspot.yaw" :step="1" @blur="handleUpdateHotspot" />
            </el-form-item>
            <!-- <el-form-item label="类型">
            <el-select v-model="hotspot.type" disabled>
              <el-option label="信息" value="info"></el-option>
              <el-option label="链接" value="link"></el-option>
              <el-option label="场景" value="scene"></el-option>
            </el-select>
          </el-form-item> -->
            <el-form-item label="热点类型" prop="job" class="form-item">
              <el-select v-model="hotspot.job" @change="handleUpdateHotspot">
                <el-option v-for="(item, index) in jobArr" :key="index" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
            <el-form-item label="标题" prop="text" class="form-item">
              <el-input v-model="hotspot.text" @blur="handleUpdateHotspot" />
            </el-form-item>
            <!-- 当类型job为scene时显示切换场景的ID的输入框（能不能优化为下来选择场景？） -->
            <!-- 当类型job为文本介绍时显示文本标题，文本介绍（textarea） -->
            <!-- 当类型job为媒体类型时显示上传组件，传给后端对应的OSSid -->
            <!-- 当类型job为tip时哈都不需要配置 -->
            <el-form-item v-if="hotspot.job === 'scene'" label="场景ID" prop="sceneId" class="form-item">
              <el-select v-model="hotspot.sceneId">
                <el-option v-for="(item, index) in sceneArr" :key="index" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
            <el-form-item v-if="hotspot.job === 'text'" label="文本标题" prop="textTitle" class="form-item">
              <el-input v-model="hotspot.textTitle" />
            </el-form-item>
            <el-form-item v-if="hotspot.job === 'text'" label="文本介绍" prop="textUrl" class="form-item">
              <el-input v-model="hotspot.textUrl" type="textarea" :rows="2" />
            </el-form-item>
            <el-form-item v-if="
              hotspot.job === 'video' ||
              hotspot.job === 'audio' ||
              hotspot.job === 'image'
            " label="媒体上传" prop="mediaUrl" class="form-item">
              <FileUpload ref="fileUpload" v-model="hotspot.mediaUrl" :file-type="hotspot.job === 'video'
                ? fileType1
                : hotspot.job === 'audio'
                  ? fileType2
                  : fileType3
                " :url="url" :dynamic-headers="dynamicHeaders" :dynamic-method="dynamicMethod"
                :dynamic-url="dynamicUrl" @input="getFirelist" :oss-id="ossId" :limit="1" @deleteFile="deleteFile"
                :drag="true" :list-type="hotspot.job === 'image' ? 'picture' : 'text'" :who="hotspot.job"
                :apply-target="hotspot" @giveMediaType="giveMediaType" />
            </el-form-item>
            <el-form-item>
              <el-button type="danger" @click="removeHotspot(index)">
                删除
              </el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { keepDecimal } from '@/utils/index'
import FileUpload from '@/components/FileUpload'
import { postOssUpload } from '@/api/oss'
import { specialRules } from '@/utils/rules'
import { deepClone } from '@/utils/index'
export default {
  name: 'PanoramaViewer',
  components: {
    FileUpload
  },
  data() {
    const validatetitle = (rule, value, callback) => {
      if (!value) {
        callback(new Error('标题不能为空'))
      } else if (!specialRules.test(value)) {
        callback(new Error('请输入合法的标题'))
      } else {
        callback()
      }
    }
    return {
      validatetitle: validatetitle,
      pannellumViewer: null,
      isAddingHotspot: false,
      hotspots: [],
      jobArr: [
        {
          label: '文本介绍',
          value: 'text'
        },
        {
          label: '切换场景',
          value: 'scene'
        },
        {
          label: '查看视频',
          value: 'video'
        },
        {
          label: '读取音频',
          value: 'audio'
        },
        {
          label: '查看图片',
          value: 'image'
        },
        {
          label: '无按钮，仅显示信息',
          value: 'tip'
        }
      ],
      fileType1: ['mp4', 'avi'],
      fileType2: ['mp3', 'mflac', 'flac'],
      fileType3: ['png', 'jpg', 'jpeg'],
      uploadParams: {
        path: '',
        name: '',
        permission: 'tenant',
        suffix: '',
        mediaType: '',
        sizeLimit: '',
        attachment: ''
      },
      url: '',
      ossId: '',
      dynamicHeaders: {},
      dynamicMethod: 'PUT',
      dynamicUrl: null,
      sceneArr: []
    }
  },
  beforeDestroy() {
    if (this.pannellumViewer) {
      this.pannellumViewer.off('mousedown', this.handleCanvasClick)
      this.pannellumViewer = null
      this.hotspots = [] // 清空hotspots数组
    }
  },
  methods: {
    giveSceneArr(arr) {
      this.sceneArr = arr
    },
    // 根据热点类型返回不同的校验规则
    getRules(jobType) {
      const baseRules = {
        text: [
          { required: true, validator: this.validatetitle, trigger: 'blur' }
        ],
        pitch: [{ required: true, message: '请输入Pitch值', trigger: 'blur' }],
        yaw: [{ required: true, message: '请输入Yaw值', trigger: 'blur' }],
        job: [{ required: true, message: '请选择热点类型', trigger: 'change' }]
      }

      // 根据不同类型添加额外规则
      if (jobType === 'scene') {
        return {
          ...baseRules,
          sceneId: [{ required: true, message: '请选择场景', trigger: 'blur' }]
        }
      }
      if (jobType === 'text') {
        return {
          ...baseRules,
          textTitle: [
            { required: true, message: '请输入文本标题', trigger: 'blur' }
          ],
          textUrl: [
            { required: true, message: '请输入文本内容', trigger: 'blur' }
          ]
        }
      }
      if (jobType === 'video' || jobType === 'audio' || jobType === 'image') {
        return {
          ...baseRules,
          mediaUrl: [
            { required: true, message: '请上传文件', trigger: 'blur' }
          ]
        }
      }

      return baseRules
    },
    // 反显处理传入的hotspots
    dealArr(arr) {
      const brr = []
      if (arr && arr.length > 0) {
        arr.map((item) => {
          const obj = {
            pitch: item.pitch,
            yaw: item.yaw,
            type: 'info',
            text: item.text,
            job: item.type,
            sceneId: '',
            textTitle: '',
            textUrl: '',
            mediaUrl: null,
            videoOidList: [],
            audioOidList: [],
            imageOidList: []
          }
          if (item.type === 'scene') {
            obj.sceneId = item.sceneId
          }
          if (item.type === 'text') {
            obj.textTitle = this.findval(item.clickHandlerArgs, 'textTitle')
            obj.textUrl = this.findval(item.clickHandlerArgs, 'url')
          }
          if (
            item.type === 'video' ||
            item.type === 'audio' ||
            item.type === 'image'
          ) {
            obj.mediaUrl = this.findval(item.clickHandlerArgs, 'url')
            // 赋予对应的OSSid
            const ossidArr = [this.findval(item.clickHandlerArgs, 'urlOssID')]
            // let ossidArr = [item.originalUrlOssID];
            switch (item.type) {
              case 'video':
                obj.videoOidList = ossidArr
                break
              case 'audio':
                obj.audioOidList = ossidArr
                break
              case 'image':
                obj.imageOidList = ossidArr
                break
              default:
                break
            }
          }
          brr.push(obj)
        })
      }
      return brr
    },
    findval(arr, key, flage = 'val') {
      let result
      if (arr && arr.length > 0) {
        arr.map((item) => {
          if (item.key === key) {
            result = item[flage]
          }
        })
      }
      return result
    },
    initPannellum(panoramaPath, arr, formValue) {
      const brr = this.dealArr(arr)
      if (arr && arr.length > 0) {
        this.hotspots = [...brr, ...this.hotspots]
      }
      this.pannellumViewer = window.pannellum.viewer('panorama', {
        type: 'equirectangular',
        panorama: panoramaPath,
        autoLoad: true,
        renderer: 'webgl',
        pitch: formValue?.initialPitch ?? 0,
        yaw: formValue?.initialYaw ?? 0,
        hfov: formValue?.initialHfov ?? 360,
        // hotSpotDebug: true, // 开启热点调试模式
        // showZoomCtrl: false, // 避免控件遮挡
        // hotSpots: [
        //   {
        //     pitch: -45,
        //     yaw: 0,
        //     type: "info",
        //     text: "init Text",
        //     URL: "https://www.baidu.com",
        //   },
        // ],
      })
      this.pannellumViewer.on('load', () => {
        this.pannellumViewer.on('mousedown', this.handleCanvasClick)
        // setTimeout(() => {
        this.updateHotspots()
        // }, 1000)
      })
    },
    startAddHotspot() {
      this.isAddingHotspot = true
      this.$message.success('请在全景图上点击添加热点')
    },
    handleCanvasClick(event) {
      if (!this.isAddingHotspot) return

      const pitch = keepDecimal(
        this.pannellumViewer.mouseEventToCoords(event)[0],
        2,
        1
      )
      const yaw = keepDecimal(
        this.pannellumViewer.mouseEventToCoords(event)[1],
        2,
        1
      )
      const newHotspot = {
        pitch: pitch,
        yaw: yaw,
        type: 'info',
        text: '热点标题',
        job: 'text',
        sceneId: '',
        textTitle: '',
        textUrl: '',
        mediaUrl: null, // 媒体路径，用于显示上传的媒体
        videoOidList: [],
        audioOidList: [],
        imageOidList: [],
        id: `hotspot-${Date.now()}`, // 使用index确保唯一性
      }

      this.hotspots.push(newHotspot)
      this.updateHotspots()
      this.isAddingHotspot = false
    },
    handleUpdateHotspot() {
      this.updateHotspots()
    },
    updateHotspots() {
      if (!this.pannellumViewer) {
        return
      }
      // 先清除所有热点
      const currentHotspots = deepClone(this.pannellumViewer.getConfig().hotSpots || [])
      // console.log(currentHotspots, 'currentHotspots')
      currentHotspots.forEach((hotspot) => {
        try {
          this.pannellumViewer.removeHotSpot(hotspot.id)
        } catch (e) {
          console.warn('移除热点失败:', e)
        }
      })
      // 添加新热点
      this.hotspots.forEach((hotspot, index) => {
        try {
          const config = {
            // id: `hotspot-${index}-${Date.now()}`, // 使用index确保唯一性
            id: hotspot.id,
            pitch: hotspot.pitch,
            yaw: hotspot.yaw,
            type: hotspot.type,
            text: hotspot.text,
            cssClass: "custom-hotspot " + hotspot.job + "-hotspot", // 自定义图标样式
          }
          this.pannellumViewer.addHotSpot(config)
        } catch (e) {
          console.error('添加热点失败:', e)
        }
      })
      // console.log(this.pannellumViewer.getConfig().hotSpots, 'hotSpots')
    },
    removeHotspot(index) {
      this.hotspots.splice(index, 1)
      this.updateHotspots()
    },
    // 整理热点数据
    async delHotspotData() {
      const isValid = await this.validateAllForms()
      if (!isValid) {
        this.$message.error('请检查所有热点表单是否填写完整')
        return false
      }
      // 处理热点数据
      if (this.hotspots.length === 0) {
        return []
      }
      //! 返回处理后的热点数据
      const arr = []
      this.hotspots.map((item) => {
        const obj = {
          pitch: item.pitch,
          yaw: item.yaw,
          type: item.job,
          text: item.text,
          cssClass: ''
        }
        if (item.job === 'scene') {
          obj.sceneId = Number(item.sceneId)
        }
        if (item.job === 'text') {
          obj.clickHandlerFunc = 'clickFunc'
          obj.clickHandlerArgs = [
            {
              key: 'type',
              val: 'text'
            },
            {
              key: 'url',
              val: item.textUrl
            },
            {
              key: 'textTitle',
              val: item.textTitle
            }
          ]
        }
        if (
          item.job === 'video' ||
          item.job === 'audio' ||
          item.job === 'image'
        ) {
          let ossid
          switch (item.job) {
            case 'video':
              ossid = item.videoOidList[0]
              break
            case 'audio':
              ossid = item.audioOidList[0]
              break
            case 'image':
              ossid = item.imageOidList[0]
              break
            default:
              break
          }
          let url
          if (Array.isArray(item.mediaUrl) && item.mediaUrl.length > 0) {
            console.log(item.mediaUrl[0], 'item.mediaUrl')
            url = item.mediaUrl[0].url
          } else {
            url = item.mediaUrl
          }
          obj.clickHandlerFunc = 'clickFunc'
          obj.clickHandlerArgs = [
            {
              key: 'type',
              val: item.job
            },
            {
              key: 'url',
              val: url
            },
            {
              key: 'urlOssID',
              val: ossid
            }
          ]
        }
        arr.push(obj)
      })
      return arr
    },
    // 校验所有表单
    async validateAllForms() {
      if (this.hotspots.length === 0) {
        return true
      } else {
        const results = await Promise.all(
          this.hotspots.map((_, index) => this.validateForm(index))
        )
        return results.every((valid) => valid)
      }
    },
    // 校验单个表单
    validateForm(index) {
      return new Promise((resolve) => {
        this.$refs[`form-${index}`][0].validate((valid) => {
          resolve(valid)
        })
      })
    },

    /* 文件上传相关 */
    giveMediaType(mediaType, who, applyTarget) {
      this.uploadParams.mediaType = mediaType
      this.uploadParams.suffix = this.uploadParams.mediaType.match(/\/(.+)/)[1]
      this.requestpostOssUpload(who)
    },
    requestpostOssUpload(who) {
      switch (who) {
        case 'video':
          this.uploadParams.name = '全景图热点视频'
          this.uploadParams.path = 'vr-hotpots-video'
          break
        case 'audio':
          this.uploadParams.name = '全景图热点音频'
          this.uploadParams.path = 'vr-hotpots-audio'
          break
        case 'image':
          this.uploadParams.name = '全景图热点图片'
          this.uploadParams.path = 'vr-hotpots-image'
          break
        default:
          break
      }
      postOssUpload(this.uploadParams)
        .then((res) => {
          if (res.success) {
            this.dynamicHeaders = res.data.headers || {}
            this.dynamicMethod = res.data.method || 'PUT'
            this.dynamicUrl = res.data.uploadUrl || ''
            this.ossId = res?.data?.ossId ?? null
          }
        })
        .catch((err) => {
          console.log(err)
        })
    },
    getFirelist(data, who, applyTarget) {
      let arr
      data.forEach((item) => {
        if (who === 'video') {
          arr = applyTarget.videoOidList
        } else if (who === 'audio') {
          arr = applyTarget.audioOidList
        } else {
          arr = applyTarget.imageOidList
        }
        if (item.ossId && !arr.includes(item.ossId)) {
          arr.push(item.ossId)
        }
      })
      this.dynamicHeaders = {}
      this.dynamicMethod = 'PUT'
      this.dynamicUrl = null
      this.ossId = ''
      console.log(this.hotspots)
    },
    deleteFile(file, who, applyTarget) {
      let flage, arr
      switch (who) {
        case 'video':
          applyTarget.videoOidList = []
          break
        case 'audio':
          applyTarget.audioOidList = []
          break
        case 'image':
          applyTarget.imageOidList = []
          break
        default:
          break
      }
      applyTarget.mediaUrl = null
      // if(typeof flage === "object" && Object.keys(flage).length > 0){

      // }
    }
  }
}
</script>

<style lang="scss" scoped>
.panorama-container {
  width: 100%;
  overflow: hidden;
}

#panorama {
  position: relative;
  overflow: hidden;
}

// .hotspot-panel {
//   padding: 10px;
//   box-sizing: border-box;
// }

.hotspot-item {
  margin-bottom: 20px;
  padding: 10px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  height: auto;
  margin-left: 10px;
}

.form-item {
  margin-bottom: 20px;
}
</style>

<style lang="scss">
.custom-hotspot {
  height: 20px;
  width: 20px;
  background-size: 100% 100%;
}

.tip-hotspot {
  background-image: url('~@/assets/images/tip.png');
}

.text-hotspot {
  background-image: url('~@/assets/images/text.png');
}

.scene-hotspot {
  background-image: url('~@/assets/images/scene.png');
}

.video-hotspot {
  background-image: url('~@/assets/images/video.png');
}

.audio-hotspot {
  background-image: url('~@/assets/images/audio.png');
}

.image-hotspot {
  background-image: url('~@/assets/images/image.png');
}
</style>
